#include <rtconfig.h>
#include <rtdevice.h>
#include "vector_parser.h"
#include <ulog.h>
#include "string.h"

#define HWTIMER_DEV_NAME   "timer0"     /* 定时器名称 */

rt_uint32_t freq = 1000000;       /* 计数频率 */
rt_device_t hw_dev = RT_NULL;   /* 定时器设备句柄 */
rt_hwtimerval_t timeout_s;      /* 定时器超时值 */

extern void OpenTestVector(void);
extern int  GetNextPattern(void);
rt_uint8_t buf_out[64];
static int32_t  g_i32DigestLength = 0;
int32_t tick_hold = 0;


int  do_compare(uint8_t *output, uint8_t *expect, int cmp_len)
{
    int   i;

    if(memcmp(expect, output, (size_t)cmp_len))
    {
        LOG_E("\nMismatch!! - %d\n", cmp_len);
        for(i = 0; i < cmp_len; i++)
            LOG_E("0x%02x    0x%02x\n", expect[i], output[i]);
        return -1;
    }
    return 0;
}


int32_t RunSHA(void)
{
    uint32_t tick_old = 0,tick_new = 0;
    struct rt_hwcrypto_ctx *ctx;
    LOG_I("Sha Test:%d byte test start\r\n",(uint32_t)g_i32DataLen / 8);
    /* 创建一个 hash 类型的上下文 */
        /* 读取定时器当前值 */
    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
    tick_old = timeout_s.sec * 1000000 + timeout_s.usec;
    ctx = rt_hwcrypto_hash_create(rt_hwcrypto_dev_default(), HWCRYPTO_TYPE_SHA512);
	
	rt_hwcrypto_hash_reset(ctx);
    if (ctx == RT_NULL)
    {
        LOG_E("create hash[%08x] context err!", HWCRYPTO_TYPE_SHA512);
        return -1;
    }
    /* 将输入数据进行 hash 运算 */
    rt_hwcrypto_hash_update(ctx, g_au8ShaData, (uint32_t)g_i32DataLen / 8);  
    /* 获得运算结果 */
    rt_err_t  err = rt_hwcrypto_hash_finish(ctx, buf_out, 64); 
    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
    tick_new = timeout_s.sec * 1000000 + timeout_s.usec;    
    LOG_I("used tick:%d,%d,%d",tick_new ,tick_old,tick_new - tick_old);
    tick_hold += tick_new - tick_old;
	LOG_HEX("SHA512   ", 8, buf_out, 64);

    rt_hwcrypto_hash_destroy(ctx);
    LOG_E("Key len= %d bits\n", g_i32DataLen);

    /* Compare calculation result with golden pattern */
    if(do_compare(&buf_out[0], &g_au8ShaDigest[0], g_i32DigestLength) < 0)
    {
        LOG_E("Compare error!\n");
        while(1);
    }else{
        LOG_I("Compare OK!\n");
    }
    LOG_I("Sha Test:%d byte test end\r\n",(uint32_t)g_i32DataLen / 8);
    return 0;
}





int sha512_test(int argc, char **argv)
{
    rt_err_t ret = RT_EOK;


    rt_hwtimer_mode_t mode;         /* 定时器模式 */

    /* 查找定时器设备 */
    hw_dev = rt_device_find(HWTIMER_DEV_NAME);
    if (hw_dev == RT_NULL)
    {
        rt_kprintf("hwtimer sample run failed! can't find %s device!\n", HWTIMER_DEV_NAME);
        return RT_ERROR;
    }

    /* 以读写方式打开设备 */
    ret = rt_device_open(hw_dev, RT_DEVICE_OFLAG_RDWR);
    if (ret != RT_EOK)
    {
        rt_kprintf("open %s device failed!\n", HWTIMER_DEV_NAME);
        return ret;
    }

    /* 设置模式为周期性定时器 */
    mode = HWTIMER_MODE_PERIOD;
    ret = rt_device_control(hw_dev, HWTIMER_CTRL_MODE_SET, &mode);
    if (ret != RT_EOK)
    {
        rt_kprintf("set mode failed! ret is :%d\n", ret);
        return ret;
    }
    rt_device_control(hw_dev, HWTIMER_CTRL_FREQ_SET, &freq);
    /* 设置定时器超时值为5s并启动定时器 */
    timeout_s.sec = 5;      /* 秒 */
    timeout_s.usec = 0;     /* 微秒 */
    rt_device_write(hw_dev, 0, &timeout_s, sizeof(timeout_s));

    /* 读取定时器当前值 */
    rt_device_read(hw_dev, 0, &timeout_s, sizeof(timeout_s));
    rt_kprintf("Read: Sec = %d, Usec = %d\n", timeout_s.sec, timeout_s.usec);


    LOG_E("sha512 test start\r\n");
    OpenTestVector();
    while(1)
    {
        /* Get data from test vector to calcualte and
           compre the result with golden pattern */
        if(GetNextPattern() < 0)
            break;

       RunSHA();
    }     
    LOG_I("Use time %d us\n",tick_hold / 10);
    tick_hold = 0;
    rt_device_close(hw_dev);      
}


MSH_CMD_EXPORT(sha512_test,  sha512 test);